<?php

/*
 * Copyright 2008 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#namespace tehframework\annotations\parsers\processors;

#use tehframework\annotations\parsers\state\ParserState;
#use tehframework\annotations\parsers\state\StateParser;
#use tehframework\annotations\parsers\state\StateProcessor;
#use tehframework\annotations\parsers\state\SelectionAware;

class AnnotationValueProcessor extends StateProcessor implements SelectionAware
{
	/**
	 * @var ArrayParser
	 */
	private $arrayParser;
	
	/**
	 * @var string
	 */
	private $value;
	
	/**
	 * @var int
	 */
	private $depth;
	
	/**
	 * @var char?
	 */
	private $enclosed;
	
	/**
	 * @var bool
	 */
	private $escaped;
	
	/**
	 * @param ArrayParser $arrayParser
	 */
	public function __construct(ArrayParser $arrayParser)
	{
		$this->arrayParser = $arrayParser;
	}
	
	public function selected()
	{
		$this->value    = '';
		$this->depth    = 1;
		$this->enclosed = null;
		$this->escaped  = false;
	}
	
	/**
	 * @param  char $token
	 * @param  StateParser $parser
	 * @throws ParserException
	 */
	public function process($token, StateParser $parser)
	{
		switch ($token)
		{
			case '"':
			case "'":
				$this->escaped = false;
				$this->value  .= $token;
				return;
			
			case '\\':
				$this->escaped = !$this->escaped;
				$this->value  .= '\\';
				return;
			
			case '(':
				if ($this->enclosed === null)
				{
					++$this->depth;
				}
				
				$this->value  .= '(';
				$this->escaped = false;
				return;
			
			case ')':
				if ($this->enclosed === null)
				{
					--$this->depth;
					
					if ($this->depth === 0)
					{
						$this->setArgumentsAndProperties($parser);
						
						$parser->changeState(ParserState::ANNOTATION, ')');
						
						return;
					}
				}
				
				$this->value .= ')';
				return;
			
			default:
				$this->value .= $token;
				return;
		}
	}
	
	private function setArgumentsAndProperties(StateParser $parser)
	{
		if ($this->value === '')
		{
			return;
		}
		
		$data = $this->arrayParser->parseArray('{' . $this->value . '}');
		
		$arguments  = array();
		$properties = array();
		
		foreach ($data as $k => $v)
		{
			if (is_int($k))
			{
				$arguments[] = $v;
			}
			else
			{
				$properties[$k] = $v;
			}
		}
		
		$parser
			->setAnnotationArguments($arguments)
			->setAnnotationProperties($properties);
	}
}